﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Transactions;
using FimetContoDeposito.DAL;
using GrayParrot.Core;

namespace FimetContoDeposito.BLL.Facades
{
    public class FornitoriFacade : FacadeBase<FornitoriFacade>
    {
        FCDContext m_ctx = null;

        public Repository<FCD_Fornitori, Guid> Repo { get; internal set; }

        public FornitoriFacade()
        {
        }

        public override void Initialize()
        {
            m_ctx = new FCDContext();
            m_ctx.Configuration.LazyLoadingEnabled = false;
            m_ctx.Configuration.ProxyCreationEnabled = false;

            Repo = this.GetRepository<FCD_Fornitori, Guid>(m_ctx);
        }

        public override void Dispose()
        {
            if (m_ctx != null)
            {
                m_ctx.Dispose();

                Repo.Dispose();
            }
        }

        public ReturnValue<bool> Add(FCD_Fornitori item)
        {
            ReturnValue<bool> retValue = new ReturnValue<bool>();

            try
            {
                if (item.Id == Guid.Empty)
                {
                    item.Id = Guid.NewGuid();
                }

                this.Repo.Add(item);
                this.Repo.Save();

                retValue.HasValue = true;
                retValue.Value = true;
            }
            catch (Exception ex)
            {
                retValue.HasError = true;
                retValue.Error = ex;
            }

            return retValue;
        }

        public ReturnValue<bool> Edit(FCD_Fornitori item)
        {
            ReturnValue<bool> retValue = new ReturnValue<bool>();

            try
            {
                this.Repo.Edit(item);
                this.Repo.Save();

                retValue.HasValue = true;
                retValue.Value = true;
            }
            catch (Exception ex)
            {
                retValue.HasError = true;
                retValue.Error = ex;
            }

            return retValue;
        }

        public ReturnValue<bool> Delete(FCD_Fornitori item)
        {
            ReturnValue<bool> retValue = new ReturnValue<bool>();

            try
            {
                this.Repo.Delete(item);
                this.Repo.Save();

                retValue.HasValue = true;
                retValue.Value = true;
            }
            catch (Exception ex)
            {
                retValue.HasError = true;
                retValue.Error = ex;
            }

            return retValue;
        }

        public ReturnValue<FCD_Fornitori> Get(Guid id)
        {
            ReturnValue<FCD_Fornitori> retValue = new ReturnValue<FCD_Fornitori>();

            try
            {
                retValue.Value = this.Repo.Get(id);
                retValue.HasValue = true;
            }
            catch (Exception ex)
            {
                retValue.HasError = true;
                retValue.Error = ex;
            }

            return retValue;
        }

        public ReturnValue<FCD_Fornitori> Get(Guid id, string includes)
        {
            ReturnValue<FCD_Fornitori> retValue = new ReturnValue<FCD_Fornitori>();

            try
            {
                retValue.Value = this.Repo.Get(x => x.Id == id, null, includes).FirstOrDefault();
                retValue.HasValue = true;
            }
            catch (Exception ex)
            {
                retValue.HasError = true;
                retValue.Error = ex;
            }

            return retValue;
        }

        public ReturnValue<IQueryable<FCD_Fornitori>> GetAll()
        {
            ReturnValue<IQueryable<FCD_Fornitori>> retValue = new ReturnValue<IQueryable<FCD_Fornitori>>();
            retValue.HasValue = false;
            retValue.Value = null;

            try
            {
                retValue.Value = this.Repo.GetAll().OrderBy(x=>x.Descrizione);
                retValue.HasValue = true;
            }
            catch (Exception ex)
            {
                retValue.HasError = true;
                retValue.Error = ex;
            }

            return retValue;
        }

        public ReturnValue<IEnumerable<NameValue<string, Guid>>> GetAllNameValue()
        {
            ReturnValue<IEnumerable<NameValue<string, Guid>>> retValue = new ReturnValue<IEnumerable<NameValue<string, Guid>>>();
            retValue.Value = null;
            retValue.HasValue = false;

            var objs = from x in m_ctx.FCD_Fornitoris
                       select new NameValue<string, Guid>()
                       {
                           value = x.Id,
                           name = x.Descrizione
                       };

            if (objs.Any())
            {
                retValue.HasValue = true;
                retValue.Value = objs;
            }
            else
            {
                NameValue<string, Guid> dummy = new NameValue<string, Guid>();
                dummy.value = Guid.Empty;
                dummy.name = "Nessun Elemento disponibile";

                List<NameValue<string, Guid>> m_l = new List<NameValue<string, Guid>>();
                m_l.Add(dummy);

                retValue.HasValue = true;
                retValue.Value = m_l.AsEnumerable();
            }

            return retValue;
        }

        public ReturnValue<bool> SaveAssociazioneClienti(Guid idFornitore, List<Guid> clienti)
        {
            ReturnValue<bool> retValue = new ReturnValue<bool>(false);

            if (clienti != null)
            {
                ReturnValue<FCD_Fornitori> m_fornitoreRes = this.Get(idFornitore);

                if (m_fornitoreRes.HasValue && m_fornitoreRes.Value != null)
                {
                    FCD_Fornitori m_fornitore = m_fornitoreRes.Value;

                    using (TransactionScope scope = new TransactionScope())
                    {
                        // aggiorna l'associazione...
                        using (CustomersFacade m_cf = CustomersFacade.Create())
                        {
                            foreach (Guid idCustomer in clienti)
                            {
                                ReturnValue<FCD_Customer> m_resC = m_cf.Get(idCustomer);
                                if (m_resC.HasValue && m_resC.Value != null)
                                {
                                    // insert into many-to-many...
                                    m_ctx.FCD_Customers.Attach(m_resC.Value);
                                    m_fornitore.FCD_Customers.Add(m_resC.Value);
                                }
                            }
                        }

                        m_ctx.SaveChanges();

                        scope.Complete();

                        retValue.HasValue = true;
                        retValue.Value = true;
                    }
                }
            }
            else
            {
                retValue.HasValue = true;
                retValue.Value = false;
                retValue.Message = "Nessuna associazione da salvare.";
            }

            return retValue;
        }

        public ReturnValue<bool> CancellaAssociazioneClienti(Guid idFornitore)
        {
            ReturnValue<bool> retValue = new ReturnValue<bool>(false);

            ReturnValue<FCD_Fornitori> m_fornitoreRes = this.Get(idFornitore, "FCD_Customers");

            if (m_fornitoreRes.HasValue && m_fornitoreRes.Value != null)
            {
                FCD_Fornitori m_fornitore = m_fornitoreRes.Value;

                using (TransactionScope scope = new TransactionScope())
                {
                    // rimuovi l'associazione...
                    List<FCD_Customer> m_associatedCustomers = m_fornitore.FCD_Customers.ToList();
                    foreach (FCD_Customer m_c in m_associatedCustomers)
                    {
                        m_fornitore.FCD_Customers.Remove(m_c);
                    }

                    m_ctx.SaveChanges();

                    scope.Complete();

                    retValue.HasValue = true;
                    retValue.Value = true;
                }
            } 

            return retValue;
        }

        /// <summary>
        /// Carica i fornitori associati ad un magazzino...
        /// </summary>
        /// <param name="idCustomer">The identifier customer.</param>
        /// <returns></returns>
        public ReturnValue<List<NameValue<string, Guid>>> LoadFornitoriByCustomer(Guid idCustomer)
        {
            ReturnValue<List<NameValue<string, Guid>>> retValue = new ReturnValue<List<NameValue<string, Guid>>>(null);
            retValue.HasValue = false;

            try
            {
                var objs = from x in m_ctx.FCD_Fornitoris
                           where x.FCD_Customers.Any(c => c.Id == idCustomer)
                           select new NameValue<string, Guid>()
                           {
                               name = x.Descrizione,
                               value = x.Id
                           };

                if (objs.Any())
                {
                    retValue.Value = objs.ToList();
                    retValue.HasValue = true;
                }
            }
            catch (Exception ex)
            {
                retValue.Error = ex;
                retValue.HasError = true;
            }
            
            return retValue;
        }

        public ReturnValue<List<NameValue<string, Guid>>> LoadFornitoriNotAssociatedToCustomers()
        {
            ReturnValue<List<NameValue<string, Guid>>> retValue = new ReturnValue<List<NameValue<string, Guid>>>(null);
            retValue.HasValue = false;

            try
            {
                var objs = from x in m_ctx.FCD_Fornitoris
                           where !x.FCD_Customers.Any()
                           select new NameValue<string, Guid>()
                           {
                               name = x.Descrizione,
                               value = x.Id
                           };

                if (objs.Any())
                {
                    retValue.Value = objs.ToList();
                    retValue.HasValue = true;
                }
            }
            catch (Exception ex)
            {
                retValue.Error = ex;
                retValue.HasError = true;
            }

            return retValue;
        }
    }
}
